#ifndef FLEET_H
#define FLEET_H



class officer;
class fCell; //strike group (sub-fleet)
class fleet; //a group of sub-fleets led by a command-ship  acts as the cmd-group on the map
class fCellLib; //a "hashtable" indexed by the x-y coords of the fCell;
class fLib;
class moveCommand;
class fireCommand;
class transferCommand;
class abortCommand;

//includes------------------------------
#include <vector>
#include <string>
#include <map>
#include <math.h>
#include "ship.h"
#include "../worldata/directs.h"
#include "../player/empire.h"
#include "../player/commands.h"
using namespace std;

//defines-------------------------------

enum fltFormation {
    spindle = 0,
    broad,
    collumn,
    siege
};

//level equation---fixme-
// levels take increasing
// amounts of exp to level
// the general equation is
// as follows
// level = k ln(exp) + c
//-----------------------
#define LEVEL_EQN(k, c, x) (k * log(x)) + c
#define OFFICER_K 1.74
#define OFFICER_C 6.01
#define STRIKE_CELL_LEVEL_CONST 5
#define FLEET_LEVEL_CONST 5

//prototypes----------------------------

//definitions---------------------------

class officer {
public:
    //constructor
    officer(string name, int pow, int speed, int cohes);
    officer(string n);
    ~officer();

    //access
    int gLevel(int exp);
    void buff(fCell* target);
    void debuff(fCell* target);

    string name;
    int exp;
    int level;
    int power;
    int speed;
    int cohes;
};

//fleet cell+++++++++++++++++++++++++++++++++++++++++++++++
// the basic unit of the players navy.  needs to be able
// to move, shoot and transfer units.  recieves buffs
// and remove buffs via the adition and removal of commanders.
//---------------------------------------------------------
class fCell {
public:
    //constructors
    fCell();
    void setParent(fleet* parent);
    void initializeLoc(int x, int y);
    ~fCell();

    //oficer transition
    void assignOfficer(officer* off);
    officer* removeOfficer();

    //compostion manipulation
    void formation(fltFormation form);
    fltFormation formation();
    void addShips(int* nShips);
    void removeShips(int* nShips);
    static void transfer(fCell* src, fCell* targ, int* nShips);

    //commands
    void autoCommands();
    void queueCommand(command* cmd);
    voley* shoot(b_type bat);
    void move(int x, int y);
    voley* takeDam(voley* vol);

    //access
    int xLoc();
    int yLoc();
    void loc(int* x, int *y);
    int level();
    int exp(int add = 0);
    int cohes(int buff);
    int power(int buff);
    int speed(int buff);
protected:
private:
    //the main body of the fleet
    fleet* parent;
    //the acting officer & cmd queue
    commandQueue* cqueue;
    officer* cmd;
    //the cell data
    int AP; //action points
    int* sNums; //the number of ships in this cell (2d array)
    int numShipTps;
    int pos[2]; //the x,y coords of the cell;
    //fleet stats
    int statPower;
    int buffPower;
    int statSpeed;
    int buffSpeed;
    int statCohes;
    int buffCohes;
    int curlevel;
    int exper;
    //formation information
    fltFormation shape; //icon shape
    direction facing; //fleet facing
};
//=========================================================
//fleet +++++++++++++++++++++++++++++++++++++++++++++++++++
// a command structure for the fleet cells.  There will only be
// a few of these.  A fleet will consist of a name, and its
// children. It will also hold teh active admiral and any
// inactive officers waiting for assignment.  It's main purpose
// is to give fleet cells more personality.  I.E. these three
// subfleets work well together, so they will work together
// to preform their assignments.  Lance cell will focus on 
// offense while shield cell defends lance.  Central cell will
// stay back and house fleet command.
//---------------------------------------------------------
class fleet {
    friend class fCell;
public:
    //constructors
    fleet(empire* parent);
    ~fleet();

    //set flag-cell
    void transferFlag(int fCId);
    //handle cell integration
    void cellDeath(fCell* killme);
    void addCell(fCell* addme);
    void setBuffs(fCell* cell);
    //static transfer funtion
    officer* assignOfficer(fCell* targ, officer* comder);
    static void transferOfficer(fleet* targ, fleet* src, officer* transfered);
    //add officers to a fleet
    void assignOfficer(officer* off);
    void retireOfficer(officer* off);
    officer* retireOfficer(int officerId);
    //assign officer from a fleet to a cell
    void giveOfficerCell(fCell* targ, officer* off);
    void giveOfficerCell(fCell* targ, int officerId);
    officer* recallOfficer(fCell* targ);
    //retiree list access
    vector<officer*>* gInactiveOfficerList();

protected:
private:
    //officers
    vector<officer*> inactive;
    officer* admiral;
    int experience;
    //fleets
    vector<fCell*> children;
    fCell* flagFleet;
    //owner
    empire* parent;
};
//=========================================================
//fleet lib++++++++++++++++++++++++++++++++++++++++++++++++
// one per player.  a list that holds the fleets.  probably
// going to hold only a few entries
//---------------------------------------------------------

class fLib {
public:
    //constructors
    fLib();
    ~fLib();
    void clean();
protected:
private:
};
//=========================================================
//fleet cell lib ++++++++++++++++++++++++++++++++++++++++++
// holds the location of each fleet in a hash map.  one per
// game.  holds all cells from each player.  a map of sorts
//---------------------------------------------------------

class fCellLib {
public:
    //constructor
    fCellLib();
    static fCellLib* getFCellLib();
    void clean();
    ~fCellLib();

    //access
    fCell* getFCell(int x, int y);
    fCell* getFCell(int id);
    void addFCell(fCell* fc);
    void moveCell(fCell* fc, int x, int y);

    void autoCommands();
protected:
private:
    map<int, map<int, fCell*>* > tbl;
};
//=========================================================
//commands ++++++++++++++++++++++++++++++++++++++++++++++++

class moveCommand : public command {
public:
    moveCommand(fCell* actor, int xdest, int ydest, bool rep = false);
    void preform();
    static void preform(fCell* actor, int xdest, int ydest);
    bool repeat();
protected:
private:
    bool dorepeat;
    fCell* actor;
    int x, y;
};

class fireCommand : public command {
public:
    fireCommand(fCell* src, fCell* targ, b_type bat);
    void preform();
    static void preform(fCell* src, fCell* targ, b_type bat);
    bool repeat();
protected:
private:
    fCell* src, targ;
    b_type bt;
};

class transferCommand : public command {
public:
    transferCommand(fCell* src, fCell* targ, int* nums);
    static void preform(fCell* src, fCell* targ, int* nums);
    void preform();
    bool repeat();
protected:
private:
    fCell *src, *targ;
    int* nums;
};

class abortCommand : public command {
public:
    abortCommand(fCell* src, fCell* targ);
    static void preform(fCell* src, fCell* targ);
    void preform();
    bool repeat();
protected:
private:
    fCell *src, *targ;
};

class splitCommand : public command {
public:
    splitCommand(fCell* src, int x, int y, int* ships);
    static void preform(fCell* src, int x, int y, int* ships);
    void preform();
protected:
private:
    fCell* src;
    int x, y;
    int* ships;
};
#endif
